﻿using System;

using RpcCacheClient.Interface;
using RpcCacheClient.Memcached;
using RpcCacheClient.Redis;

namespace RpcCacheClient.Cache
{
    public class CacheController : ICacheController
    {
        public CacheType CacheType { get; private set; }
        private bool _isInit=false;
        private int _db;
        private ICacheController _CacheClient = null;

        public bool IsEnable
        {
            get => RpcCacheService.CheckIsInit(this.CacheType);
        }
        protected internal ICacheController CacheClient
        {
            get
            {
                if(_CacheClient == null)
                {
                    _CacheClient = _CreateCache();
                }
                return _CacheClient;
            }
        }
        public CacheController()
        {
            _isInit = false;
        }
        protected CacheController(CacheType cacheType,int db)
        {
            this._isInit = true;
            this._db = db;
            this.CacheType = cacheType;
        }
        private ICacheController _CreateCache()
        {
            if (!_isInit)
            {
                this.CacheType = RpcCacheService.DefCacheType;
                this._db = RpcCacheService.RedisDb;
            }
            if(this.CacheType == CacheType.Local)
            {
                return new Local.LocalCache();
            }
            return this.CacheType == CacheType.Memcached ? new MemcachedCache() : new RedisCache(this._db);
        }
      
       
        public T AddOrUpdate<T>(string key, T data, Func<T, T, T> upFunc)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.AddOrUpdate<T>(key, data, upFunc);
        }

        public T AddOrUpdate<T>(string key, T data, Func<T, T, T> upFunc, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.AddOrUpdate<T>(key, data, upFunc, expiresAt);
        }


        public T GetOrAdd<T>(string key, T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.GetOrAdd<T>(key, data);
        }

        public T GetOrAdd<T>(string key, T data, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.GetOrAdd<T>(key, data, expiresAt);
        }
        public bool Remove(string key)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Remove(key);
        }

        public bool Set<T>(string key, T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Set<T>(key, data);
        }

        public bool Set<T>(string key, T data, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Set<T>(key, data, expiresAt);
        }
        public bool Set<T>(string key, T data, DateTime expires)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Set<T>(key, data, expires);
        }
        public bool TryGet<T>(string key, out T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryGet<T>(key, out data);
        }


        public bool TryRemove<T>(string key, out T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryRemove<T>(key, out data);
        }
        public bool TryRemove<T>(string key, Func<T, bool> func, out T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryRemove<T>(key, func, out data);
        }
        public T TryUpdate<T>(string key, T data, Func<T, T, T> upFunc)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryUpdate<T>(key, data, upFunc);
        }

        public bool Replace<T>(string key, T data, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Replace<T>(key, data, expiresAt);
        }

        public bool Replace<T>(string key, T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Replace<T>(key, data);
        }

        public bool Add<T>(string key, T data, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Add<T>(key, data, expiresAt);
        }

        public bool Add<T>(string key, T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.Add<T>(key, data);
        }

        public T TryUpdate<T>(string key, T data, Func<T, T, T> upFunc, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryUpdate<T>(key, data, upFunc, expiresAt);
        }

        public bool TryUpdate<T>(string key, Func<T, T> upFunc, out T data)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryUpdate<T>(key, upFunc, out data);
        }

        public bool TryUpdate<T>(string key, Func<T, T> upFunc, out T data, TimeSpan expiresAt)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryUpdate<T>(key, upFunc, out data, expiresAt);
        }

        public bool TryRemove<T>(string key, Func<T, bool> func)
        {
            key = RpcCacheService.FormatKey(key);
            return this.CacheClient.TryRemove<T>(key, func);
        }
    }
}
